#include <string.h>
#include <windows.h>
#include <SetupAPI.h>
#include <INITGUID.H>

#include "share/std_err.h"
#include "public.h"

#pragma comment(lib, "setupapi.lib")

#define ASSERT(exp) do {                     \
	if(!(exp)) {                             \
		printf("ASSERT failed: %s\r\n", #exp); \
		return -1;                           \
	}                                        \
} while(0)

int device_get_count(const GUID* guid) {
    if(!guid) return 0;
    HDEVINFO device_info = SetupDiGetClassDevs((LPGUID)guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
    if(device_info == INVALID_HANDLE_VALUE) return 0;

    SP_DEVICE_INTERFACE_DATA device_interface = { 0 };
    device_interface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);

    unsigned index = 0;
    while(SetupDiEnumDeviceInterfaces(device_info, NULL, guid, index, &device_interface)) index++;

    SetupDiDestroyDeviceInfoList(device_info);
    return index;
}

std_err_t device_get_path(int idx, const GUID* guid, char* device_path) {
    if(idx < 0 || !guid || !device_path) return STD_ERR_INVALID_ARG;
    std_err_t err = STD_ERR_OK;

    HDEVINFO device_info = SetupDiGetClassDevs((LPGUID)guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
    if(device_info == INVALID_HANDLE_VALUE) {
        printf("SetupDiGetClassDevs(): failed !\r\n");
        return STD_ERR_FAIL;
    }

    SP_DEVICE_INTERFACE_DATA device_interface = { 0 };
    device_interface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);

    // 设备详细信息
    PSP_DEVICE_INTERFACE_DETAIL_DATA dev_detail = NULL;

    // enumerate through devices
    for(unsigned index = 0; SetupDiEnumDeviceInterfaces(device_info, NULL, guid, index, &device_interface); ++index) {
        // 如果不是指定的设备，则继续下一个
        if(index < idx) continue;

        // get required buffer size
        unsigned long detail_length = 0;
        if(!SetupDiGetDeviceInterfaceDetail(device_info, &device_interface, NULL, 0, &detail_length, NULL) && GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
            printf("SetupDiGetDeviceInterfaceDetail(): get length failed !\r\n");
            err = STD_ERR_FAIL;
            goto _final;
        }

        // allocate space for device interface detail
        dev_detail = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(detail_length);
        if(!dev_detail) {
            printf("malloc(): failed !\r\n");
            err = STD_ERR_NO_MEM;
            goto _final;
        }
        dev_detail->cbSize = sizeof(*dev_detail);

        // get device interface detail
        if(!SetupDiGetDeviceInterfaceDetail(device_info, &device_interface, dev_detail, detail_length, NULL, NULL)) {
            printf("SetupDiGetDeviceInterfaceDetail(): get detail failed !\r\n");
            err = STD_ERR_FAIL;
            goto _final;
        }

        // 拷贝设备路径
        strncpy(device_path, dev_detail->DevicePath, 256);
        break;
    }

_final:
    if(dev_detail) free(dev_detail);
    SetupDiDestroyDeviceInfoList(device_info);
    return err;
}

int main(int argc, char** argv) {
    DWORD ret;
    char  strbuf[256];

    ret = device_get_count(&GUID_DEVINTERFACE_zyhello);
    ret = device_get_path(ret-1, &GUID_DEVINTERFACE_zyhello, strbuf);

    HANDLE hdev = CreateFile(strbuf, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	ASSERT(hdev != INVALID_HANDLE_VALUE);

	while(1) {
        printf("Wait for event0 ...\n");
		ret = WaitForSingleObject(hdev, 100000);
        printf("wait ret = %d\n", ret);
		if(ret == WAIT_OBJECT_0) {
			ret = ReadFile(hdev, &ret, sizeof(ret), NULL, NULL);
			ASSERT(ret == TRUE);
            printf("read = %d\n", ret);
		}

		printf("Press ctrl-c to exit, any other key to continue ...\n");
		(void)getchar();
	}

	CloseHandle(hdev);
	return 0;
}
